﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Common
{
    public class AwaitLock : IDisposable
    {
        private static SemaphoreSlim _global = new SemaphoreSlim(1);
        private SemaphoreSlim _semaphore;
        private Action _onDispose;

        private AwaitLock(bool isGlobal)
        {
            if (isGlobal)
            {
                _semaphore = _global;
            }
            else
            {
                _semaphore = new SemaphoreSlim(1);
            }
        }

        public void Dispose()
        {
            if (_onDispose != null)
            {
                _onDispose();
                _onDispose = null;
            }

            _semaphore.Release();
        }

        public async Task<AwaitLock> Lock()
        {
            await _semaphore.WaitAsync();
            return this;
        }

        public async Task<AwaitLock> Lock(CancellationToken cancellationToken)
        {
            await _semaphore.WaitAsync(cancellationToken);
            return this;
        }

        public async Task<AwaitLock> Lock(Action onDispose)
        {
            await _semaphore.WaitAsync();
            _onDispose = onDispose;
            return this;
        }

        public static AwaitLock CreateIndividual()
        {
            return new AwaitLock(isGlobal: false);
        }

        public static AwaitLock CreateGlobal()
        {
            return new AwaitLock(isGlobal: true);
        }
    }
}
